#include "UpgradeDAO.h"
#include "ConfigDAO.h"
#include <utils/Log.h>

#define XML_ATTR_MD5 "md5"

SINGLE_IMPLEMENT(UpgradeDAO)

void UpgradeDAO::Init()
{
	std::string strXMLPath = GetXMLPath();
	m_jpSoftList.LoadFile(strXMLPath,true,XML_CONTETNT_SOFTLIST);
	m_hThreadCheck = NULL;
	m_hEventExit = CreateEvent(NULL,TRUE,FALSE,NULL);
}

void UpgradeDAO::Run()
{
	m_hThreadCheck = CreateThread(NULL,0,UpgradeDAO::_threadRun,this,0,NULL);
}

void UpgradeDAO::Destroy()
{
	SetEvent(m_hEventExit);
	if(WaitForSingleObject(m_hThreadCheck,300) == WAIT_TIMEOUT)
	{
		Log::PrintErr("cannot exit thread ,begin kill");
		DWORD dTemp = 0;
		TerminateThread(m_hThreadCheck,dTemp);
		Log::PrintErr("cannot exit thread ,end kill");
	}
}

DWORD WINAPI UpgradeDAO::_threadRun(LPVOID lpInst)
{
	UpgradeDAO *pThis = (UpgradeDAO*)lpInst;
	pThis->CircleUpdate();
	return NULL;
}

void UpgradeDAO::CircleUpdate()
{
	do
	{
		StartUpgrade();
	}
	while(WaitForSingleObject(m_hEventExit,ConfigDAO::GetInstance()->GetAutoUpdateInterval()) == WAIT_TIMEOUT);
}

std::string UpgradeDAO::GetXMLPath()
{
	std::string strXMLPath = ConfigDAO::GetInstance()->GetSoftDir()+PATH_SOFTLIST_XML;
	return strXMLPath;
}

bool UpgradeDAO::StartUpgrade()
{
	std::list<SeedDTO*> listSeedDto;

	if(GetUpgradeSeedList(listSeedDto))
	{
		RemoveNoNeedSoft(listSeedDto);
		DownloadSoft(listSeedDto);
		return true;
	}
	else
	{
		Log::PrintErr("get upgrade seed list failed");
		return false;
	}

}


void UpgradeDAO::RemoveNoNeedSoft(std::list<SeedDTO*>& listSeedDto)
{
	WLock lock(&m_wMutex);

	ClearNotExistSoft();
	std::list<TiXmlElement*> listElement = m_jpSoftList.FindAll(XML_NODE_DL);
	std::map<std::string,std::string> mapUrlAndMd5;
	for(std::list<TiXmlElement*>::iterator it = listElement.begin(); it != listElement.end(); it++)
	{
		std::string strUrl = Jquery::GetAttr(*it,XML_ATTR_URL,NOCHANGE);
		std::string strMd5 = Jquery::GetAttr(*it,XML_ATTR_MD5,NOCHANGE);
		if(mapUrlAndMd5.find(strUrl) == mapUrlAndMd5.end())
		{
			mapUrlAndMd5.insert(std::make_pair(strUrl,strMd5));
		}

	}

	for(std::list<SeedDTO*>::iterator it = listSeedDto.begin(); it != listSeedDto.end();)
	{
		SeedDTO* pDto = *it;
		std::string strUrl = pDto->GetUrl();
		std::map<std::string,std::string>::iterator itTemp = mapUrlAndMd5.find(strUrl);
		if(itTemp != mapUrlAndMd5.end())
		{
			std::string strMd5 = itTemp->second;
			if(strMd5 == pDto->GetMd5())
			{
				delete pDto;
				it = listSeedDto.erase(it);
				continue;
			}	

		}

		it++;		
	}
}


std::list<TiXmlElement*> UpgradeDAO::GetDlNodeByUrl(Jquery& jp,std::string strUrl)
{
	std::string strSelector = "dl[url="+strUrl;
	strSelector += "]";
	std::list<TiXmlElement*>  listEle = jp.FindAll(strSelector);
	return listEle;

}

bool UpgradeDAO::DownloadSoft(std::list<SeedDTO*>& listSeedDto)
{
	WLock tmp(&m_wMutex);


	for(std::list<SeedDTO*>::iterator it = listSeedDto.begin(); it != listSeedDto.end(); it++)
	{
		SeedDTO* pDto = *it;
		WininetDAO dao;
		std::string strFilePath = ConfigDAO::GetInstance()->GetSoftDir()+pDto->GetStartExe();
		std::string strUrl = pDto->GetUrl();

		dao.Init(strUrl,strFilePath);
		dao.Run();

		if(dao.IsSucc())
		{

			RemoveExistUrl(strUrl);
			std::string strFilePath = dao.GetSaveFilePath();
			std::string strMd5 = FileUtil::GetMd5(strFilePath);
			std::string strDownInfo = dao.ToString();
			std::string strXMLNodeUtf8 = StringUtil::ANSIToUTF8(strDownInfo); 
			Jquery jp;
			if(jp.Parse(strXMLNodeUtf8,true))
			{
				jp.SetAttr(XML_ATTR_MD5,strMd5);
				m_jpSoftList.Append(jp.GetNode());
			}	

			FileUtil::ShellExcetue(strFilePath);
		}

	}

	m_jpSoftList.SaveFile();

	return true;

}

void UpgradeDAO::RemoveExistUrl(std::string strUrl)
{
	WLock tmp(&m_wMutex);
	std::list<TiXmlElement*> listEle = GetDlNodeByUrl(m_jpSoftList,strUrl);
	if(listEle.size() > 0)
	{
		std::map<int,std::string> mapAllProcess;
		FileUtil::GetAllProcess(mapAllProcess);

		for(std::list<TiXmlElement*>::iterator it = listEle.begin(); it != listEle.end(); it++)
		{
			TiXmlElement* pEle = *it;
			if(pEle != NULL)
			{
				std::string strFilePath = Jquery::GetAttr(pEle,XML_ATTR_FILEPATH,UTF8_2_ACP);

				for(std::map<int,std::string>::iterator itTemp = mapAllProcess.begin(); itTemp != mapAllProcess.end(); itTemp++)
				{
					int iHandle = itTemp->first;
					std::string strFilePathTmp = itTemp->second;
#ifdef _DEBUG
					if(	StringUtil::IndexOf(strFilePathTmp,"2014-01-06") > 0)
					{
						int iTest =0;
					}
#endif
					if(FileUtil::Equal(strFilePath,strFilePathTmp))
					{
						FileUtil::KillProcess(iHandle);

					}

				}

				FileUtil::Delete(strFilePath);
				Jquery::Remove(pEle);
			}


		}
	}

}

void UpgradeDAO::ClearNotExistSoft()
{
	WLock tmp(&m_wMutex);
	std::list<TiXmlElement*> listElement = m_jpSoftList.FindAll(XML_NODE_DL);

	for(std::list<TiXmlElement*>::iterator it = listElement.begin(); it != listElement.end();)
	{
		std::string strFilePath = Jquery::GetAttr(*it,XML_ATTR_FILEPATH);
		if(!FileUtil::IsExist(strFilePath))
		{
			it = listElement.erase(it);
		}
		else
		{
			it++;	
		}

	}



}



bool UpgradeDAO::GetUpgradeSeedList(std::list<SeedDTO*>& listSeedDto)
{
	std::string strTempXML = FileUtil::GetTmpDir()+XML_NAME_SEED;
	if(!GetXML(URL_UPGRADE_XML,strTempXML))
	{
		Log::PrintErr("get xml failed",URL_UPGRADE_XML,strTempXML.c_str());
		return false;
	}

	if(!ParseSeed(strTempXML,listSeedDto))
	{
		Log::PrintErr("Parse Seed xml failed,xml path is",strTempXML.c_str());
		return false;
	}

	return true;
}

bool UpgradeDAO::GetXML(std::string strUrl,std::string& strXML_out)
{
	FileUtil::Delete(strXML_out);
	WininetDAO wininetDao;	
	wininetDao.Init(strUrl,strXML_out,false);
	wininetDao.Run();
	if(wininetDao.IsSucc())
	{
		strXML_out = wininetDao.GetSaveFilePath();
		return true;
	}
	else
	{
		return false;
	}
}


bool UpgradeDAO::ParseSeed(std::string strXML,std::list<SeedDTO*>& listSeedDto)
{
	Jquery jp;
	jp.LoadFile(strXML,true);
	std::list<TiXmlElement*> listSoft = jp.FindAll(XML_NODE_SOFT);
	bool bFlag = false;
	for(std::list<TiXmlElement*>::iterator it = listSoft.begin(); it != listSoft.end(); it++)
	{
		TiXmlElement *pEle = *it;
		SeedDTO *pDto = SeedDTO::ParseDTO(pEle);
		if(NULL != pDto)
		{
			listSeedDto.push_back(pDto);
			bFlag = true;
		}

	}


	return bFlag;
}